package com.yao2san.sim.storage.client.core.manager;

import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.COSObjectSummary;
import com.qcloud.cos.model.ListObjectsRequest;
import com.qcloud.cos.model.ObjectListing;
import com.qcloud.cos.model.RenameRequest;
import com.tencent.cloud.CosStsClient;
import com.tencent.cloud.Response;
import com.yao2san.sim.storage.client.util.StorageUtil;
import com.yao2san.sim.storage.client.config.TencentCosProperties;
import com.yao2san.sim.storage.client.core.auth.Credentials;
import com.yao2san.sim.storage.client.core.enums.StorageType;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

/**
 * @author wxg
 **/
public class TencentCosStorageManager extends AbstractStorageManager {

    private final TencentCosProperties tencentCosProperties;
    private final COSClient cosClient;

    private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public TencentCosStorageManager(COSClient cosClient, TencentCosProperties tencentCosProperties) {
        this.tencentCosProperties = tencentCosProperties;
        this.cosClient = cosClient;
    }


    @Override
    public boolean exist(String object) {
        return cosClient.doesObjectExist(tencentCosProperties.getBucket(), object);
    }

    @Override
    public void delete(String object) {
        cosClient.deleteObject(tencentCosProperties.getBucket(), object);
    }

    @Override
    public void rename(String source, String target) throws IOException {
        RenameRequest renameRequest = new RenameRequest(tencentCosProperties.getBucket(), source, target);
        cosClient.rename(renameRequest);
    }

    @Override
    public void copy(String source, String target, boolean keepSource) throws IOException {
        cosClient.copyObject(tencentCosProperties.getBucket(), source, tencentCosProperties.getBucket(), target);
    }

    @Override
    public List<StorageObject> list(String prefix) throws IOException {
        return list(prefix, null);
    }

    @Override
    public List<StorageObject> list(String prefix, String startAfter) throws IOException {
        String bucket = tencentCosProperties.getBucket();
        String endpoint = tencentCosProperties.getEndpoint();
        ListObjectsRequest request = new ListObjectsRequest();
        request.setBucketName(bucket);
        request.setPrefix(prefix);
        request.setMarker(startAfter);
        ObjectListing objects = cosClient.listObjects(request);
        List<COSObjectSummary> objectSummaries = objects.getObjectSummaries();
        List<StorageObject> storageObjects = new ArrayList<>();
        objectSummaries.forEach(v -> {
            StorageObject storageObject = StorageObject.builder()
                    .object(v.getKey())
                    .size(v.getSize())
                    .lastModified(v.getLastModified().getTime())
                    .storageType(StorageType.ALI_OSS.name())
                    .url(getUrl(endpoint, bucket, v.getKey()))
                    .isDir(false)
                    .build();
            storageObjects.add(storageObject);

        });
        return storageObjects;
    }

    private String getUrl(String endpoint, String bucket, String object) {
        return bucket + "." + endpoint + "/" + object;
    }

    @Override
    public String getName() {
        return StorageType.TENCENT_COS.name();
    }


    @Override
    public Credentials credentials(long durationSeconds) {
        Credentials cachedCredentials = getCachedCredentials();
        if (cachedCredentials != null) {
            return cachedCredentials;
        }
        TreeMap<String, Object> config = new TreeMap<>();

        try {
            config.put("secretId", tencentCosProperties.getAccessKey());
            config.put("secretKey", tencentCosProperties.getSecretKey());
            config.put("durationSeconds", Long.valueOf(durationSeconds).intValue());
            config.put("bucket", tencentCosProperties.getBucket());
            config.put("region", tencentCosProperties.getRegion());
            config.put("allowPrefixes", new String[]{"*"});

            String[] allowActions = new String[]{"*"};
            config.put("allowActions", allowActions);

            Response response = CosStsClient.getCredential(config);
            com.tencent.cloud.Credentials credentials = response.credentials;
            Credentials c = Credentials.builder().accessKey(credentials.tmpSecretId)
                    .secretKey(credentials.tmpSecretKey)
                    .securityToken(credentials.sessionToken)
                    .expiration(LocalDateTime.now().plusSeconds(durationSeconds).format(DateTimeFormatter.ofPattern(DATE_FORMAT)))
                    .build();
            cachedCredentials(c, durationSeconds);
            return c;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public Credentials getCachedCredentials() {
        return CREDENTIALS_CACHE.get(getKey());
    }

    public void cachedCredentials(Credentials credentials, long seconds) {
        CREDENTIALS_CACHE.put(getKey(), credentials, seconds * 1000);
    }

    public String getKey() {
        return StorageUtil.md5(this.tencentCosProperties.toString());
    }
}
